﻿#include "ZTcpClient.h"

#include <xil_printf.h>
#include <lwip/sockets.h>
#include "lwip/netif.h"

#include <utility>

#include "lwip/init.h"
#include "lwip/inet.h"
#include "netif/xadapter.h"

#define PLATFORM_EMAC_BASEADDR XPAR_XEMACPS_0_BASEADDR

// 当前支持的mac数量,即支持多少的tcp
constexpr int macSize{2};
// 独一无二的mac地址
static uint8_t macAddress[macSize][6] = {
    {0x00, 0x0a, 0x35, 0x00, 0x01, 0x02},
    {0x00, 0x0a, 0x35, 0x00, 0x01, 0x03},
};
// mac地址索引
static int macIdx{0};

ZTcpClient::ZTcpClient(std::string selfIP, std::string serverIP,
                       int serverPort,
                       std::function<void(const std::string &)> callFunc)
  : server_netif_(new netif{}),
    selfIP_(std::move(selfIP)),
    serverIP_(std::move(serverIP)),
    serverPort_(serverPort),
    callFunc_(std::move(callFunc)) {
  sys_thread_new("ZTcpClientThread", &ZTcpClient::initialize, this,
                 1024, DEFAULT_THREAD_PRIO);
}

void ZTcpClient::writeData(const char *dataPtr, int size) {
  // 待发送的数据大小
  int remaindSize{size};
  // 循环发送数据
  while (remaindSize > 0) {
    auto sendSize{lwip_send(socket_, dataPtr + (size - remaindSize),
                            remaindSize, MSG_MORE)};
    remaindSize -= sendSize;
  }
}

void ZTcpClient::initialize(void *self) {
  // 只能使用预定义的mac,不能超过
  if (macIdx >= macSize) {
    xil_printf("tcp client size>%d\n", macSize);
  }
  auto that{(ZTcpClient *) self};

  lwip_init();

  /* Add network interface to the netif_list, and set it as default */
  if (!xemac_add(that->server_netif_, NULL, NULL, NULL,
                 macAddress[macIdx++], PLATFORM_EMAC_BASEADDR)) {
    xil_printf("Error adding N/W interface\n");
    return;
  }
  netif_set_default(that->server_netif_);
  /* specify that the network if is up */
  // 使能
  netif_set_up(that->server_netif_);
  // 参数配置
  that->assignDefaultIp();
  // 启动收发监听
  sys_thread_new("xemacif_input_thread",
                 (void(*)(void *)) xemacif_input_thread, that->server_netif_,
                 1024,
                 DEFAULT_THREAD_PRIO);
  // 创建socket
  that->socket_ = socket(AF_INET, SOCK_STREAM, 0);
  if (that->socket_ < 0) {
    xil_printf("TCP Client: Error in creating Socket\n");
    return;
  }
  // socket配置
  sockaddr_in address{};
  address.sin_family = AF_INET;
  address.sin_port = htons(that->serverPort_);
  address.sin_addr.s_addr = inet_addr(that->serverIP_.c_str());
  if (connect(that->socket_, (sockaddr *) &address, sizeof(address)) < 0) {
    xil_printf("TCP Client: Error on tcp_connect\n");
    close(that->socket_);
    return;
  }

  while (true) {
    static char recvBuffer[1024]{};
    u8_t apiflags = MSG_WAITALL;
    auto recvSize = lwip_recv(that->socket_, recvBuffer, sizeof(recvBuffer),
                              apiflags);
    that->callFunc_(std::string(recvBuffer, recvSize));
  }

  vTaskDelete(NULL);
}

void ZTcpClient::assignDefaultIp() {
  int err{};
  err = inet_aton(this->selfIP_.c_str(), &this->server_netif_->ip_addr);
  if (!err)
    xil_printf("Invalid default IP address: %d\n", err);

  err = inet_aton("255.255.255.0", &this->server_netif_->netmask);
  if (!err)
    xil_printf("Invalid default IP MASK: %d\n", err);

  /* 将自定义ip的最后1个数字替换为1 */
  auto idx = this->selfIP_.find_last_of('.');
  std::string selfGW_Addr{};
  if (idx == std::string::npos) {
    throw std::runtime_error("invalid ip");
  } else {
    // 将最后的字符替换为1
    selfGW_Addr = this->selfIP_.substr(0, idx + 1) += "1";
  }
  err = inet_aton(selfGW_Addr.c_str(), &this->server_netif_->gw);
  if (!err)
    xil_printf("Invalid default gateway address: %d\n", err);
}